<template>
  <div class="pro-wang-editor-container">
    <div class="pro-alert" v-if="showInfo">
      <pro-editor-info :proAlertInfo="proAlertInfo" />
    </div>
    <div
      class="pro-container"
      :class="{
        radius,
        border,
        'full-screen-container': fullScreen,
        'not-full-screen-container': !fullScreen
      }"
      :id="editorId"
    >
      <div class="pro-back" v-if="fullScreen">
        <span @click="fullScreen = false">
          <icons name="i-left" fill="black" /> 返回
        </span>
      </div>
      <div class="pro-top">
        <Toolbar
          class="pro-tool-bar"
          :editor="editorRef"
          :mode="mode"
          :defaultConfig="toolBarConfigProps"
        />
      </div>

      <div class="pro-bottom">
        <Editor
          class="pro-editor"
          :class="{ preview }"
          :style="{
            height
          }"
          v-model="valueHtml"
          :defaultConfig="editorConfigProps"
          :mode="mode"
          @onCreated="handleCreated"
          @onChange="onChange"
        />
        <Transition v-if="!fullScreen" name="slide-fade">
          <div
            v-show="preview"
            ref="previewRef"
            :style="{
              height
            }"
            class="pro-wang-html"
          />
        </Transition>
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup name="ProWangEditor">
/**  https://www.wangeditor.com/v5/toolbar-config.html  **/
import '@wangeditor/editor/dist/css/style.css'
import './registerWangEditor'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { IToolbarConfig, IEditorConfig } from '@wangeditor/editor'

import {
  defaultEditorConfig,
  defaultUploadConfig,
  defaultUploadImageConfig,
  defaultUploadVideoConfig,
  defaultUploadFileConfig
} from './defaultConfig'

import usePreview from './hooks/usePreview'
import useConfigMerge from './hooks/useConfigMerge'
import { UploadConfig } from './configType'

// 1. 重置功能 ok
// 2. 图片、视频、文件上传 （需接口调通后测试）ok
// 3. 同步预览 ok
// 4. 提示 ok
// 5. 上传前钩子限制文件大小、类型 ok

interface wangeditorPropsType {
  // 默认模式与简洁模式
  mode?: 'default' | 'simple'
  /**
   *  工具栏设置,可以为配置项对象，也可以为一个接收默认配置项为参数返回配置项的函数
   *  {
   *    toolbarKeys: Array<string | IMenuGroup>  -配置工具栏，显示哪些菜单，以及菜单的排序、分组
   *    insertKeys: {                            -在当前 toolbarKeys 的基础上继续插入新菜单
   *      index: number
   *      keys: string | Array<string | IMenuGroup>
   *    }
   *    excludeKeys: Array<string>               -如果仅仅想排除掉某些菜单，其他都保留，可以使用 excludeKeys 来配置
   *    modalAppendToBody: boolean               -将菜单弹出的 modal 添加到 body 下
   *  }
   *   **/
  toolBarConfig?: (
    config: Partial<IToolbarConfig>
  ) => Partial<IToolbarConfig> | Partial<IToolbarConfig>
  editorConfig?: Partial<IEditorConfig>
  defaultUploadConfig?: UploadConfig
  uploadImageConfig?: Record<string, unknown>
  uploadVideoConfig?: Record<string, unknown>
  uploadFileConfig?: Record<string, unknown>
  height?: string | 'auto'
  // 内容
  modelValue?: string
  // 是否在初次渲染时显示预览窗口
  openPreview?: boolean
  // 富文本边框弧度：方形|圆形
  radius?: boolean
  //是否添加边框
  border?: boolean
  // 显示提示信息
  showInfo?: boolean
  // 全屏
  isFullScreen?: boolean
  // 预览
  isPreview?: boolean
}

const props = withDefaults(defineProps<wangeditorPropsType>(), {
  editorConfig: () => defaultEditorConfig,
  uploadImageConfig: () => defaultUploadImageConfig,
  uploadVideoConfig: () => defaultUploadVideoConfig,
  defaultUploadConfig: () => defaultUploadConfig,
  uploadFileConfig: () => defaultUploadFileConfig,
  mode: 'default',
  height: 'auto',
  modelValue: '',
  radius: true,
  border: true,
  showInfo: true
})

const valueHtml = ref(props.modelValue)
const editorRef = shallowRef()

// 提示信息、editorConfig合并、上传函数定义
const { editorConfigProps, toolBarConfigProps } = useConfigMerge(props)
const proAlertInfo = computed(() => {
  const { uploadImage, uploadVideo, uploadAttachment } =
    editorConfigProps.value.MENU_CONF
  return [uploadImage, uploadVideo, uploadAttachment]
})

const emits = defineEmits([
  'update:modelValue',
  'update:isFullScreen',
  'update:isPreview'
])

// 预览功能
const previewRef = ref<HTMLElement | null>(null)
const {
  preview,
  onChange,
  initOnPreview,
  initEditorPreviewScroll,
  initPreviewDomScroll,
  removePreviewDomScroll,
  removeEditorPreviewScroll
} = usePreview(editorRef, previewRef, props, (val) => {
  emits('update:isPreview', val)
})

// 全屏功能(重写)
const fullScreen = ref(!!props.isFullScreen)
const initOnNewFullScreen = () => {
  editorRef.value.on('onNewFullScreen', () => {
    fullScreen.value = !fullScreen.value
    if (props.isFullScreen) preview.value = false
    onChange()
  })
}

watch(fullScreen, (val) => {
  emits('update:isFullScreen', val)
})

watch(
  () => props.isFullScreen,
  (val) => {
    fullScreen.value = val as boolean
  }
)
// 全屏功能 end

// 编辑器id
const editorId = computed(() => {
  return (editorRef.value && editorRef.value.id) || ''
})

// 记录 editor 实例
const handleCreated = (editor) => {
  editorRef.value = editor
  initOnNewFullScreen()
  initOnPreview()
  initEditorPreviewScroll()
  initPreviewDomScroll()
  initFileMenu()
}

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  removeEditorPreviewScroll()
  removePreviewDomScroll()
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})

// 下载与预览文件
const initFileMenu = () => {
  editorRef.value.on('downloadFile', (val) => {
    if (!val) window['$message'].warning('下载失败，请重新尝试!')
  })

  editorRef.value.on('previewFile', (val) => {
    if (!val) window['$message'].warning('预览失败，请重新尝试!')
    else previewFile(val)
  })
}

// 预览文件
const previewFile = (val) => {
  console.log(val)
}

// 更新v-model值
watch(valueHtml, (val) => {
  emits('update:modelValue', `<div class="pro-wang-html">${val}</div>`)
})

// 只读状态监听切换
watch(
  () => props.editorConfig.readOnly,
  (val) => {
    val ? editorRef.value.disable() : editorRef.value.enable()
  }
)
</script>
<style lang="less" scoped>
@import './styles/qq-doc.less';
@radius: 6px;
.pro-wang-editor-container {
  height: 100%;

  .pro-alert {
    margin: 10px 0;
  }

  .pro-tool-bar {
    border-bottom: 1px solid #e8e8e8;
  }

  .pro-back {
    background: #fff;
    padding: 10px;

    border-bottom: 1px solid #e8e8e8;
    span {
      cursor: pointer;
    }
  }

  .pro-bottom {
    display: flex;
    position: relative;
    justify-content: space-between;

    .pro-editor {
      flex: 1;
      overflow: auto;
    }

    .pro-wang-html {
      width: 560px;
      padding: 0 10px;
      overflow-y: auto;
      background-color: #f8f7f7;
    }
  }

  .radius.not-full-screen-container {
    :deep(.w-e-bar) {
      border-radius: @radius @radius 0 0;
    }
    :deep(.w-e-text-container) {
      border-radius: 0 0 0 @radius;
      min-width: 400px;
    }
    .pro-wang-html {
      border-radius: 0 0 @radius 0;
    }
    border-radius: @radius;
  }

  .border {
    border: 1px solid #efeff5;
  }

  .slide-fade-leave-active,
  .slide-fade-enter-active {
    transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
  }

  .slide-fade-enter-from,
  .slide-fade-leave-to {
    opacity: 0;
    width: 0 !important;
  }

  :deep(.w-e-bar-item) {
    padding: 4px 6px !important;
  }
}

[data-theme='dark'] {
  .pro-wang-html {
    color: var(--w-e-toolbar-color);
  }
}
</style>
<style lang="less">
[data-theme='dark'] {
  --w-e-textarea-bg-color: #333;
  --w-e-textarea-color: #fff;
  --w-e-textarea-border-color: #ccc;
  --w-e-textarea-slight-border-color: #e8e8e8;
  --w-e-textarea-slight-color: #d4d4d4;
  --w-e-textarea-slight-bg-color: #f5f2f0;
  --w-e-textarea-selected-border-color: #b4d5ff;
  --w-e-textarea-handler-bg-color: #4290f7;
  --w-e-toolbar-color: #595959;
  --w-e-toolbar-bg-color: #ccc;
  --w-e-toolbar-active-color: #333;
  --w-e-toolbar-active-bg-color: #f1f1f1;
  --w-e-toolbar-disabled-color: #999;
  --w-e-toolbar-border-color: #e8e8e8;
  --w-e-modal-button-bg-color: #fafafa;
  --w-e-modal-button-border-color: #d9d9d9;
}
</style>
